Python装饰器

🤔


装饰器介绍

Python装饰器是程序开发中经常使用到的功能,熟练掌握装饰器会让你的编程思路更加广阔

要理解装饰器,首先要先理解:

  1. 在 Python 中“函数是一等对象” 。即函数是一种特殊类型的变量,可以和其余变量一样,可以作为参数传递给函数,也可以作为返回值返回。Python 中的整数、字符串和字典等都是一等对象。
  2. 函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。

装饰器实现

装饰器本质上是python函数,它可以使其他函数在不需要做代码变动的情况下增加新的功能,装饰器返回值也是一个函数对象。

以下是一个简单的例子:
假设现在有一个函数sayHi,用来输出一句话

1
2
3
4
def sayHi():
print('Hello, World')
s = sayHi
s()

输出:Hello, World

我想希望在不修改sayHi函数的情况下在其之前再输出一句话,这种在代码运行期间动态增加功能的方式,称之为“装饰器”。
本质上,装饰器就是一个返回函数的高阶函数

我们可以这么写:

1
2
3
4
5
6
7
8
9
10
def sayName(func):
def inner():
print("I'm Yu")
return func
return inner()

def sayHi():
print('Hello, World')
s = sayName(sayHi)
s()

输出:

1
2
I'm Yu
Hello, World

但代码美中不足的是,我们每次给sayHi增加功能都需要用到类似s = sayName(sayHi)这句话。
python为了简化这种情况,提供了一个语法糖“@”。

简化上边的代码:

1
2
3
4
5
6
7
8
9
10
11
def sayName(func):
def inner():
print("I'm Yu")
return func()
return inner

@sayName
def sayHi():
print('Hello, World')

sayHi()

输出:

1
2
I'm Yu
Hello, World


装饰器原理

以上代码中,首先,在装饰器函数sayName中,sayName需要接受一个参数func,在其内部又定义了一个inner函数,在inner函数中增加一句输出,并返回func对象,然后sayName函数返回内部函数inner,其实就是一个闭包函数。
接下来在sayHi上边增加一个@sayName,其意义就是在python解释器之行到此处时,会调用装饰器函数(sayName),并把被装饰得函数(sayHi)作为参数传入。此时的sayHi已经不是未加装饰时的函数了,而是指向sayName.inner函数地址。在接下来调用sayHi()时,其实就是调用sayName.inner。


有参函数装饰

之前的例子是对无参函数的装饰,如果装饰带参数的函数该如何处理?

1
2
3
4
5
6
7
8
9
10
11
def sayName(func):
def inner(name):
print("I'm Yu")
return func(name)
return inner

@sayName
def sayHi(name):
print('Hi,' + name)

sayHi('siri')

输出:

1
2
I'm Yu
Hi,siri


两个装饰器装饰函数

这里测试两个装饰器装饰一个函数的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def sayName(func):
print('name')
def inner():
print("I'm Yu")
return func()
return inner

def sayAge(func):
print('age')
def inner():
print("i'm 30")
return func()
return inner

@sayName
@sayAge
def sayHi():
print('Hello, World')

sayHi()

输出:

1
2
3
4
5
age
name
I'm Yu
i'm 30
Hello, World

接下来分析输出这个结果的原因:
首先,python解释器执行到第一个装饰器@sayName,在接下来发现装饰器下边不是一个函数而是另一个装饰器,解释器会执行第二个的装饰器@sayAge,然后把sayHi函数传入装饰器,所以首先输出了“age”,当@sayAge装饰完成,此时的sayHi函数地址指向了sayAge.inner的地址,解释器会返回去执行@sayName装饰器来装饰新的sayHi,从而输出了“name”,接着函数当前指向sayName.inner会先输出“I’m Yu”,在这里返回的func()其实就是返回的sayAge.inner,所以在下面输出i’m 30,最后输出原本sayHi的“Hello, World”


有参装饰器

下边是装饰器带参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def now(time):
def sayName(func):
def inner(name):
print('现在是: %s' % time)
print("I'm Yu")
return func(name)
return inner
return sayName

@now('2016/10/30')
def sayHi(name):
print('Hello,' + name)

sayHi('siri')

输出:

1
2
3
现在是: 2016/10/30
I'm Yu
Hello,siri


以上就是python装饰器的相关介绍

宇 wechat
扫描二维码,订阅微信公众号